import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { DatabaseService } from './database.service';
import {
  CreateXLayerTokenDto,
  ContributeXLayerTokenDto,
  BuyXLayerTokenDto,
  SellXLayerTokenDto,
  PrepareXLayerBuyDto,
  PrepareXLayerSellDto,
  PrepareXLayerApproveDto,
  PrepareXLayerCreateDto,
  ConfirmXLayerCreateDto,
  ConfirmXLayerBuyDto,
} from '../dto/xlayer.dto';
import * as fs from 'fs';
import * as path from 'path';
import { ethers } from 'ethers';
import { XLayerContractHelper } from '../contracts/xlayer-contract';
import { RealtimeGateway } from '../gateways/realtime.gateway';

export interface XLayerToken {
  id: string;
  launchId: number;
  tokenAddress: string;
  creator: string;
  name: string;
  symbol: string;
  description: string;
  website?: string;
  telegram?: string;
  twitter?: string;
  imageUrl?: string;
  targetAmount: string;
  raisedAmount: string;
  tokenPrice: string;
  createdAt: number;
  deadline: number;
  launched: boolean;
  cancelled: boolean;
  currentPrice?: string;
  priceChange24h?: number;
  volume24h?: string;
  marketCap?: string;
  holders?: number;
}

export interface XLayerContribution {
  id: string;
  launchId: number;
  contributor: string;
  amount: string;
  tokensReceived: string;
  timestamp: number;
  txHash: string;
}

@Injectable()
export class XLayerService {
  private provider: ethers.JsonRpcProvider;
  private readonly LAUNCHPAD_ADDRESS: string;

  constructor(
    private databaseService: DatabaseService,
    private readonly contractHelper: XLayerContractHelper,
    @Inject(forwardRef(() => RealtimeGateway))
    private readonly realtimeGateway: RealtimeGateway,
  ) {
    // Initialize X Layer provider
    if (!process.env.XLAYER_RPC_URL) {
      throw new Error('XLAYER_RPC_URL environment variable is required');
    }
    if (!process.env.XLAYER_LAUNCHPAD_ADDRESS) {
      throw new Error(
        'XLAYER_LAUNCHPAD_ADDRESS environment variable is required',
      );
    }

    const rpcUrl = process.env.XLAYER_RPC_URL;
    this.LAUNCHPAD_ADDRESS = process.env.XLAYER_LAUNCHPAD_ADDRESS;
    this.provider = new ethers.JsonRpcProvider(rpcUrl);
  }

  async getStats() {
    try {
      // Get stats from database
      const result = await this.databaseService.query(`
        SELECT 
          COUNT(*) as totalTokens,
          COALESCE(SUM(CASE WHEN raised_amount IS NOT NULL THEN CAST(raised_amount AS DECIMAL) ELSE 0 END), 0) as totalVolume,
          COUNT(DISTINCT creator) as activeTraders,
          COUNT(CASE WHEN launched = true THEN 1 END) as successfulLaunches
        FROM xlayer_tokens
      `);

      const stats = result.rows[0];

      return {
        totalTokens: parseInt(stats.totaltokens) || 0,
        totalVolume: stats.totalvolume || '0',
        activeTraders: parseInt(stats.activetraders) || 0,
        totalLaunches: parseInt(stats.totaltokens) || 0,
        successfulLaunches: parseInt(stats.successfullaunches) || 0,
      };
    } catch (error) {
      console.error('Error getting X Layer stats:', error);
      return {
        totalTokens: 0,
        totalVolume: '0',
        activeTraders: 0,
        totalLaunches: 0,
        successfulLaunches: 0,
      };
    }
  }

  async getTokens(options: {
    page: number;
    limit: number;
    search?: string;
    filter?: 'all' | 'active' | 'launched' | 'cancelled';
    sort?:
      | 'newest'
      | 'oldest'
      | 'price_high'
      | 'price_low'
      | 'market_cap'
      | 'volume';
  }) {
    try {
      let whereClause = 'WHERE 1=1';
      const params: any[] = [];
      let paramIndex = 1;

      // Apply search filter
      if (options.search) {
        whereClause += ` AND (name ILIKE $${paramIndex} OR symbol ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`;
        params.push(`%${options.search}%`);
        paramIndex++;
      }

      // Apply status filter
      if (options.filter && options.filter !== 'all') {
        switch (options.filter) {
          case 'active':
            whereClause += ` AND launched = false AND cancelled = false AND deadline > ${Date.now() / 1000}`;
            break;
          case 'launched':
            whereClause += ` AND launched = true`;
            break;
          case 'cancelled':
            whereClause += ` AND cancelled = true`;
            break;
        }
      }

      // Apply sorting
      let orderClause = 'ORDER BY created_at DESC';
      switch (options.sort) {
        case 'newest':
          orderClause = 'ORDER BY created_at DESC';
          break;
        case 'oldest':
          orderClause = 'ORDER BY created_at ASC';
          break;
        case 'price_high':
          orderClause =
            'ORDER BY CAST(current_price AS DECIMAL) DESC NULLS LAST';
          break;
        case 'price_low':
          orderClause =
            'ORDER BY CAST(current_price AS DECIMAL) ASC NULLS LAST';
          break;
        case 'market_cap':
          orderClause = 'ORDER BY CAST(market_cap AS DECIMAL) DESC NULLS LAST';
          break;
        case 'volume':
          orderClause = 'ORDER BY CAST(volume_24h AS DECIMAL) DESC NULLS LAST';
          break;
      }

      const offset = (options.page - 1) * options.limit;
      params.push(options.limit, offset);

      const query = `
        SELECT * FROM xlayer_tokens 
        ${whereClause} 
        ${orderClause} 
        LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
      `;

      const result = await this.databaseService.query(query, params);

      // Get total count
      const countQuery = `SELECT COUNT(*) FROM xlayer_tokens ${whereClause}`;
      const countResult = await this.databaseService.query(
        countQuery,
        params.slice(0, -2),
      );
      const total = parseInt(countResult.rows[0].count);

      const tokens = result.rows.map((row) => this.mapRowToToken(row));

      return {
        tokens,
        pagination: {
          page: options.page,
          limit: options.limit,
          total,
          totalPages: Math.ceil(total / options.limit),
        },
      };
    } catch (error) {
      console.error('Error getting X Layer tokens:', error);
      return {
        tokens: [],
        pagination: {
          page: options.page,
          limit: options.limit,
          total: 0,
          totalPages: 0,
        },
      };
    }
  }

  /**
   * 调试代币状态 - 比较数据库和智能合约的数据
   */
  async debugTokenState(launchId: number) {
    try {
      console.log(`Debugging token state for launch ${launchId}`);
      
      // 获取数据库数据
      const dbToken = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      
      if (!dbToken) {
        throw new Error('Token not found in database');
      }
      
      // 获取智能合约数据
      const contractInfo = await this.contractHelper.getLaunchInfo(launchId);
      
      // 获取数据库中的贡献记录
      const contributions = await this.databaseService.xLayerContribution.findMany({
        where: { launchId },
        orderBy: { timestamp: 'desc' }
      });
      
      const dbData = {
        launchId: dbToken.launchId,
        tokenAddress: dbToken.tokenAddress,
        creator: dbToken.creator,
        raisedAmount: dbToken.raisedAmount,
        tokenPrice: dbToken.tokenPrice,
        currentPrice: dbToken.currentPrice,
        tokensSold: dbToken.tokensSold,
        launched: dbToken.launched,
        cancelled: dbToken.cancelled,
        contributionsCount: contributions.length,
        totalContributions: contributions.reduce((sum, c) => sum + parseFloat(c.amount), 0).toString()
      };
      
      const contractData = {
        tokenAddress: contractInfo.tokenAddress,
        creator: contractInfo.creator,
        raisedAmount: ethers.formatEther(contractInfo.raisedAmount),
        currentPrice: ethers.formatEther(contractInfo.currentPrice),
        tokensSold: ethers.formatEther(contractInfo.tokensSold),
        launched: contractInfo.launched,
        cancelled: contractInfo.cancelled,
        targetAmount: ethers.formatEther(contractInfo.targetAmount)
      };
      
      // 比较差异
      const differences = [];
      if (dbData.raisedAmount !== contractData.raisedAmount) {
        differences.push({
          field: 'raisedAmount',
          database: dbData.raisedAmount,
          contract: contractData.raisedAmount
        });
      }
      if (dbData.tokensSold !== contractData.tokensSold) {
        differences.push({
          field: 'tokensSold',
          database: dbData.tokensSold,
          contract: contractData.tokensSold
        });
      }
      if (dbData.launched !== contractData.launched) {
        differences.push({
          field: 'launched',
          database: dbData.launched,
          contract: contractData.launched
        });
      }
      
      return {
        success: true,
        launchId,
        database: dbData,
        contract: contractData,
        differences,
        contributions: contributions.slice(0, 5) // 最近5个贡献
      };
    } catch (error) {
      console.error(`Error debugging token state for launch ${launchId}:`, error);
      throw error;
    }
  }

  /**
   * 强制刷新代币价格（从智能合约获取最新价格）
   */
  async refreshTokenPrice(launchId: number) {
    try {
      console.log(`Refreshing price for launch ${launchId}`);
      
      // 获取链上最新信息
      const launchInfo = await this.contractHelper.getLaunchInfo(launchId);
      
      const currentPrice = ethers.formatEther(launchInfo.currentPrice);
      const tokensSold = ethers.formatEther(launchInfo.tokensSold);
      const raisedAmount = ethers.formatEther(launchInfo.raisedAmount);
      
      console.log(`Contract data for launch ${launchId}:`, {
        currentPrice,
        tokensSold,
        raisedAmount,
        launched: launchInfo.launched
      });
      
      // 更新数据库
      const updated = await this.databaseService.xLayerToken.updateMany({
        where: { launchId },
        data: {
          currentPrice,
          tokensSold,
          raisedAmount,
          launched: launchInfo.launched,
          cancelled: launchInfo.cancelled,
        },
      });
      
      console.log(`Updated ${updated.count} records with new price: ${currentPrice} OKB`);
      
      // 验证更新是否成功
      const updatedToken = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      
      return {
        success: true,
        message: 'Price refreshed successfully',
        data: {
          launchId,
          oldPrice: updatedToken?.tokenPrice || 'unknown',
          newPrice: currentPrice,
          tokensSold,
          raisedAmount,
          launched: launchInfo.launched
        }
      };
    } catch (error) {
      console.error(`Error refreshing price for launch ${launchId}:`, error);
      throw error;
    }
  }

  /**
   * 手动触发毕业（用于调试或紧急情况）
   */
  async manualGraduateToken(launchId: number, creatorPrivateKey?: string) {
    try {
      console.log(`Manual graduation attempt for launch ${launchId}`);
      
      // 获取代币信息
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      if (!token) throw new Error('Launch not found');
      
      if (token.launched) {
        return { success: true, message: 'Token already graduated' };
      }
      
      // 检查是否达到毕业条件
      const raisedAmount = parseFloat(token.raisedAmount);
      const targetAmount = parseFloat(token.targetAmount);
      const graduationThreshold = 0.8; // 80%
      
      if (raisedAmount < targetAmount * graduationThreshold) {
        throw new Error(`Not enough funds raised. Need ${targetAmount * graduationThreshold} OKB, only have ${raisedAmount} OKB`);
      }
      
      // 如果提供了私钥，尝试调用智能合约毕业函数
      if (creatorPrivateKey) {
        try {
          // TODO: 实现智能合约手动毕业调用
          console.log('Manual contract graduation not yet implemented');
        } catch (error) {
          console.error('Smart contract graduation failed:', error);
          // 即使智能合约调用失败，我们也继续更新数据库状态
        }
      }
      
      // 同步状态
      const syncResult = await this.syncTokenWithContract(launchId);
      
      return {
        success: true,
        message: 'Manual graduation completed',
        syncResult
      };
    } catch (error) {
      console.error(`Manual graduation failed for launch ${launchId}:`, error);
      throw error;
    }
  }

  /**
   * 同步智能合约和数据库状态
   */
  async syncTokenWithContract(launchId: number) {
    try {
      console.log(`Syncing token with contract for launchId: ${launchId}`);
      
      // 获取链上最新状态
      const launchInfo = await this.contractHelper.getLaunchInfo(launchId);
      
      console.log(`Contract state for launch ${launchId}:`, {
        raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
        targetAmount: ethers.formatEther(launchInfo.targetAmount),
        launched: launchInfo.launched,
        cancelled: launchInfo.cancelled,
        currentPrice: ethers.formatEther(launchInfo.currentPrice)
      });
      
      // 更新数据库状态
      const updated = await this.databaseService.xLayerToken.updateMany({
        where: { launchId },
        data: {
          raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
          currentPrice: ethers.formatEther(launchInfo.currentPrice),
          launched: launchInfo.launched,
          cancelled: launchInfo.cancelled,
        },
      });
      
      console.log(`Updated ${updated.count} records for launchId ${launchId}`);
      
      return {
        success: true,
        contractState: {
          raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
          targetAmount: ethers.formatEther(launchInfo.targetAmount),
          launched: launchInfo.launched,
          cancelled: launchInfo.cancelled,
          currentPrice: ethers.formatEther(launchInfo.currentPrice)
        }
      };
    } catch (error) {
      console.error(`Error syncing token ${launchId} with contract:`, error);
      throw error;
    }
  }

  async getToken(id: string) {
    try {
      const result = await this.databaseService.query(
        'SELECT * FROM xlayer_tokens WHERE id = $1',
        [id],
      );

      if (result.rows.length === 0) {
        return null;
      }

      return this.mapRowToToken(result.rows[0]);
    } catch (error) {
      console.error('Error getting X Layer token:', error);
      return null;
    }
  }

  async createToken(createTokenDto: CreateXLayerTokenDto) {
    try {
      // 1. 调用链上 createTokenLaunch
      console.log('Creating token launch with params:', createTokenDto);
      const onchain = await this.contractHelper.createLaunch({
        name: createTokenDto.name,
        symbol: createTokenDto.symbol,
        description: createTokenDto.description,
        website: createTokenDto.website,
        telegram: createTokenDto.telegram,
        twitter: createTokenDto.twitter,
        targetEth: createTokenDto.targetAmount.toString(),
        creatorPrivateKey: createTokenDto.creatorPrivateKey,
      });
      console.log('Onchain result:', onchain);

      // 2. 读取链上 launch 详情
      console.log('Getting launch info for launchId:', onchain.launchId);
      const launchInfo = await this.contractHelper.getLaunchInfo(
        onchain.launchId,
      );
      console.log('Launch info from contract:', launchInfo);

      // 3. 使用 Prisma 创建 token 记录
      const newToken = await this.databaseService.xLayerToken.create({
        data: {
          launchId: Number(onchain.launchId),
          tokenAddress: launchInfo.tokenAddress,
          creator: launchInfo.creator,
          name: launchInfo.name,
          symbol: launchInfo.symbol,
          description: launchInfo.description,
          website: createTokenDto.website || null,
          telegram: createTokenDto.telegram || null,
          twitter: createTokenDto.twitter || null,
          imageUrl: createTokenDto.imageUrl || null,
          targetAmount: ethers.formatEther(launchInfo.targetAmount),
          raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
          tokenPrice: ethers.formatEther(launchInfo.currentPrice),
          createdAt: Math.floor(Date.now() / 1000),
          deadline: launchInfo.deadline,
          launched: launchInfo.launched,
          cancelled: launchInfo.cancelled,
          currentPrice: ethers.formatEther(launchInfo.currentPrice),
        },
      });

      return {
        ...this.mapPrismaTokenToInterface(newToken),
        txHash: onchain.txHash,
      };
    } catch (error) {
      console.error('Error creating X Layer token:', error);
      throw error;
    }
  }

  async contribute(tokenId: string, contributeDto: ContributeXLayerTokenDto) {
    try {
      // First get the token
      const token = await this.getToken(tokenId);
      if (!token) {
        throw new Error('Token not found');
      }

      // Create contribution record
      const contributionId = `xlayer_contrib_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

      const contributionQuery = `
        INSERT INTO xlayer_contributions (
          id, launch_id, contributor, amount, tokens_received, timestamp, tx_hash
        ) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *
      `;

      const tokensReceived = (
        parseFloat(contributeDto.ethAmount.toString()) /
        parseFloat(token.tokenPrice)
      ).toString();

      const contributionValues = [
        contributionId,
        token.launchId,
        contributeDto.contributorAddress,
        contributeDto.ethAmount.toString(),
        tokensReceived,
        Math.floor(Date.now() / 1000),
        '', // txHash - will be provided later
      ];

      await this.databaseService.query(contributionQuery, contributionValues);

      // Update token raised amount
      const newRaisedAmount = (
        parseFloat(token.raisedAmount) +
        parseFloat(contributeDto.ethAmount.toString())
      ).toString();

      await this.databaseService.query(
        'UPDATE xlayer_tokens SET raised_amount = $1 WHERE id = $2',
        [newRaisedAmount, tokenId],
      );

      // Check if token should be launched (reached target)
      if (parseFloat(newRaisedAmount) >= parseFloat(token.targetAmount)) {
        await this.databaseService.query(
          'UPDATE xlayer_tokens SET launched = true WHERE id = $1',
          [tokenId],
        );

        // TODO: Emit launch event
      }

      return {
        success: true,
        tokensReceived,
        newRaisedAmount,
      };
    } catch (error) {
      console.error('Error contributing to X Layer token:', error);
      throw error;
    }
  }

  /** 购买 (buyTokens) 并记录 */
  async buy(dto: BuyXLayerTokenDto) {
    // 使用 Prisma 查找 token（launchId 是唯一字段）
    const token = await this.databaseService.xLayerToken.findFirst({
      where: { launchId: dto.launchId },
    });
    if (!token) throw new Error('Launch not found');

    // 执行链上购买
    const onchain: any = await this.contractHelper.buyTokens({
      launchId: dto.launchId,
      ethAmount: dto.ethAmount.toString(),
      buyerPrivateKey: dto.buyerPrivateKey,
    });

    // 读取链上最新数据
    const launchInfo = await this.contractHelper.getLaunchInfo(dto.launchId);

    // 使用 Prisma 更新 token 信息
    await this.databaseService.xLayerToken.updateMany({
      where: { launchId: dto.launchId },
      data: {
        raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
        currentPrice: ethers.formatEther(launchInfo.currentPrice),
      },
    });

    const tokensReceivedStr = onchain.tokensReceived
      ? ethers.formatUnits(onchain.tokensReceived, 18)
      : '0';
    console.log('DEBUG: onchain result =', {
      txHash: onchain.txHash,
      tokensReceived: onchain.tokensReceived
        ? ethers.formatUnits(onchain.tokensReceived, 18)
        : 'undefined',
      newPrice: onchain.newPrice
        ? ethers.formatUnits(onchain.newPrice, 18)
        : 'undefined',
      ethReceived: onchain.ethReceived
        ? ethers.formatUnits(onchain.ethReceived, 18)
        : 'undefined',
    });
    console.log('DEBUG: tokensReceivedStr =', tokensReceivedStr);

    // 使用 Prisma 创建贡献记录（使用 unchecked 创建以避免关系问题）
    await this.databaseService.xLayerContribution.create({
      data: {
        launchId: dto.launchId,
        contributor: dto.buyerAddress,
        amount: dto.ethAmount.toString(),
        tokensReceived: tokensReceivedStr,
        tradeType: 'buy',
        txHash: onchain.txHash,
        timestamp: Math.floor(Date.now() / 1000),
      },
    });
    return {
      txHash: onchain.txHash,
      tokensReceived: onchain.tokensReceived
        ? ethers.formatUnits(onchain.tokensReceived, 18)
        : '0',
      newPrice: onchain.newPrice
        ? ethers.formatEther(onchain.newPrice)
        : undefined,
    };
  }

  /** 出售 (sellTokens) */
  async sell(dto: SellXLayerTokenDto) {
    const tokenRow = await this.databaseService.query(
      'SELECT * FROM xlayer_tokens WHERE launch_id = $1',
      [dto.launchId],
    );
    if (tokenRow.rows.length === 0) throw new Error('Launch not found');
    const onchain: any = await this.contractHelper.sellTokens({
      launchId: dto.launchId,
      tokenAmount: dto.tokenAmount.toString(),
      sellerPrivateKey: dto.sellerPrivateKey,
    });
    const launchInfo = await this.contractHelper.getLaunchInfo(dto.launchId);
    await this.databaseService.query(
      'UPDATE xlayer_tokens SET current_price=$1 WHERE launch_id=$2',
      [ethers.formatEther(launchInfo.currentPrice), dto.launchId],
    );
    return {
      txHash: onchain.txHash,
      ethReceived: onchain.ethReceived
        ? ethers.formatEther(onchain.ethReceived)
        : undefined,
      newPrice: onchain.newPrice
        ? ethers.formatEther(onchain.newPrice)
        : undefined,
    };
  }

  async getUserTokens(address: string) {
    try {
      const result = await this.databaseService.query(
        'SELECT * FROM xlayer_tokens WHERE creator = $1 ORDER BY created_at DESC',
        [address],
      );

      return result.rows.map((row) => this.mapRowToToken(row));
    } catch (error) {
      console.error('Error getting user X Layer tokens:', error);
      return [];
    }
  }

  async getUserContributions(address: string) {
    try {
      const result = await this.databaseService.query(
        `
        SELECT c.*, t.name, t.symbol, t.image_url 
        FROM xlayer_contributions c
        LEFT JOIN xlayer_tokens t ON c.launch_id = t.launch_id
        WHERE c.contributor = $1 
        ORDER BY c.timestamp DESC
      `,
        [address],
      );

      return result.rows.map((row) => ({
        id: row.id,
        launchId: row.launch_id,
        contributor: row.contributor,
        amount: row.amount,
        tokensReceived: row.tokens_received,
        timestamp: row.timestamp,
        txHash: row.tx_hash,
        refunded: row.refunded,
        refundTxHash: row.refund_tx_hash,
        tokenName: row.name,
        tokenSymbol: row.symbol,
        tokenImageUrl: row.image_url,
      }));
    } catch (error) {
      console.error('Error getting user contributions:', error);
      return [];
    }
  }

  async uploadImage(file: Express.Multer.File) {
    try {
      // Create uploads directory if it doesn't exist
      const uploadsDir = path.join(process.cwd(), 'uploads', 'images');
      if (!fs.existsSync(uploadsDir)) {
        fs.mkdirSync(uploadsDir, { recursive: true });
      }

      // Generate unique filename
      const fileExtension = path.extname(file.originalname);
      const filename = `token-${Date.now()}-${Math.random().toString().substr(2, 9)}${fileExtension}`;
      const filePath = path.join(uploadsDir, filename);

      // Write file
      fs.writeFileSync(filePath, file.buffer);

      // Return URL
      const baseUrl = process.env.BASE_URL || 'http://localhost:7172';
      const imageUrl = `${baseUrl}/uploads/images/${filename}`;

      return { url: imageUrl };
    } catch (error) {
      console.error('Error uploading X Layer image:', error);
      throw error;
    }
  }

  async getTokenChart(tokenId: string, timeframe: '1h' | '24h' | '7d' | '30d') {
    try {
      // TODO: Implement actual price history from blockchain or price feeds
      // For now, return mock data
      const token = await this.getToken(tokenId);
      if (!token) {
        throw new Error('Token not found');
      }

      const prices = this.generateMockPriceData(token, timeframe);

      return {
        prices,
        timeframe,
      };
    } catch (error) {
      console.error('Error getting token chart data:', error);
      return {
        prices: [],
        timeframe,
      };
    }
  }

  async syncTokenFromContract(tokenId: string) {
    try {
      // 获取数据库中的代币信息
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { id: tokenId },
      });

      if (!token) {
        throw new Error('Token not found');
      }

      // 从合约获取最新状态
      const contractHelper = new XLayerContractHelper();
      const launchInfo = await contractHelper.getLaunchInfo(token.launchId);

      // 更新数据库中的状态
      const updatedToken = await this.databaseService.xLayerToken.update({
        where: { id: tokenId },
        data: {
          tokenAddress: launchInfo.tokenAddress,
          raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
          tokenPrice: ethers.formatEther(launchInfo.currentPrice),
          launched: launchInfo.launched,
          cancelled: launchInfo.cancelled,
          // 可以添加更多需要同步的字段
        },
      });

      console.log(`Token ${tokenId} synced from contract:`, {
        launched: launchInfo.launched,
        cancelled: launchInfo.cancelled,
        raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
      });

      return this.mapPrismaTokenToInterface(updatedToken);
    } catch (error) {
      console.error('Error syncing token from contract:', error);
      throw error;
    }
  }

  async getTokenHolders(tokenId: string) {
    try {
      // TODO: Implement token holder tracking
      return [];
    } catch (error) {
      console.error('Error getting token holders:', error);
      return [];
    }
  }

  async getTokenTransactions(tokenId: string, limit: number) {
    try {
      const result = await this.databaseService.query(
        `
        SELECT * FROM xlayer_contributions 
        WHERE launch_id = (SELECT launch_id FROM xlayer_tokens WHERE id = $1)
        ORDER BY timestamp DESC
        LIMIT $2
      `,
        [tokenId, limit],
      );

      return result.rows.map((row) => ({
        id: row.id,
        type: 'contribution',
        contributor: row.contributor,
        amount: row.amount,
        tokensReceived: row.tokens_received,
        timestamp: row.timestamp,
        txHash: row.tx_hash,
      }));
    } catch (error) {
      console.error('Error getting token transactions:', error);
      return [];
    }
  }

  // 辅助函数：检查是否是有效的 wei 值（大于 1e15 的数值可能是 wei）
  private isValidWeiValue(value: string | number): boolean {
    if (!value) return false;
    const numValue = typeof value === 'string' ? parseFloat(value) : value;
    return numValue > 1e15; // 大于 0.001 ETH 的 wei 值
  }

  private mapRowToToken(row: any): XLayerToken {
    return {
      id: row.id,
      launchId: row.launch_id,
      tokenAddress: row.token_address,
      creator: row.creator,
      name: row.name,
      symbol: row.symbol,
      description: row.description,
      website: row.website,
      telegram: row.telegram,
      twitter: row.twitter,
      imageUrl: row.image_url,
      // 将 wei 转换为 ETH 进行显示
      targetAmount: this.isValidWeiValue(row.target_amount) 
        ? ethers.formatEther(row.target_amount) 
        : row.target_amount,
      raisedAmount: this.isValidWeiValue(row.raised_amount) 
        ? ethers.formatEther(row.raised_amount) 
        : row.raised_amount,
      tokenPrice: row.token_price,
      createdAt: row.created_at,
      deadline: row.deadline,
      launched: row.launched,
      cancelled: row.cancelled,
      currentPrice: row.current_price,
      priceChange24h: row.price_change_24h,
      volume24h: row.volume_24h,
      marketCap: row.market_cap,
      holders: row.holders,
    };
  }

  private mapPrismaTokenToInterface(token: any): XLayerToken {
    return {
      id: token.id,
      launchId: token.launchId,
      tokenAddress: token.tokenAddress,
      creator: token.creator,
      name: token.name,
      symbol: token.symbol,
      description: token.description,
      website: token.website,
      telegram: token.telegram,
      twitter: token.twitter,
      imageUrl: token.imageUrl,
      // 将 wei 转换为 ETH 进行显示
      targetAmount: this.isValidWeiValue(token.targetAmount) 
        ? ethers.formatEther(token.targetAmount) 
        : token.targetAmount,
      raisedAmount: this.isValidWeiValue(token.raisedAmount) 
        ? ethers.formatEther(token.raisedAmount) 
        : token.raisedAmount,
      tokenPrice: token.tokenPrice,
      createdAt: token.createdAt,
      deadline: token.deadline,
      launched: token.launched,
      cancelled: token.cancelled,
      currentPrice: token.currentPrice,
      priceChange24h: token.priceChange24h
        ? Number(token.priceChange24h)
        : undefined,
      volume24h: token.volume24h,
      marketCap: token.marketCap,
      holders: token.holdersCount,
    };
  }

  private generateMockPriceData(token: XLayerToken, timeframe: string) {
    const now = Date.now();
    const data = [];
    const points =
      timeframe === '1h'
        ? 60
        : timeframe === '24h'
          ? 24
          : timeframe === '7d'
            ? 7
            : 30;
    const interval =
      timeframe === '1h' ? 60000 : timeframe === '24h' ? 3600000 : 24 * 3600000;

    const basePrice = parseFloat(token.tokenPrice);
    let currentPrice = basePrice;

    for (let i = points; i >= 0; i--) {
      const timestamp = now - i * interval;

      // Simulate price movement
      const change = (Math.random() - 0.5) * 0.1;
      currentPrice = Math.max(basePrice * 0.5, currentPrice * (1 + change));

      const volume = Math.random() * 10;

      data.push({
        timestamp,
        price: currentPrice,
        volume,
      });
    }

    return data;
  }

  /**
   * 准备买入交易 - 返回交易数据供前端钱包签名
   */
  async prepareBuyTransaction(dto: PrepareXLayerBuyDto) {
    // 验证代币存在
    const token = await this.databaseService.xLayerToken.findFirst({
      where: { launchId: dto.launchId },
    });
    if (!token) throw new Error('Launch not found');

    // 检查代币是否已经毕业（不能再购买）
    if (token.launched) {
      throw new Error('Token has already launched and graduated to DEX. Trading is no longer available on the bonding curve.');
    }

    // 检查代币是否已取消
    if (token.cancelled) {
      throw new Error('Token launch has been cancelled');
    }

    // 检查是否过期
    if (Date.now() / 1000 > token.deadline) {
      throw new Error('Token launch has expired');
    }

    // 生成交易数据
    const contract = new ethers.Contract(
      this.LAUNCHPAD_ADDRESS,
      [
        'function buyTokens(uint256 _launchId) external payable',
        'function calculateTokensForETH(uint256 _launchId, uint256 _ethAmount) external view returns (uint256)',
      ],
      this.provider,
    );

    // 计算将获得的代币数量
    const ethAmountWei = ethers.parseEther(dto.ethAmount.toString());
    const tokensToReceive = await contract.calculateTokensForETH(
      dto.launchId,
      ethAmountWei,
    );

    // 构建交易数据
    const txData = contract.interface.encodeFunctionData('buyTokens', [
      dto.launchId,
    ]);

    return {
      success: true,
      transaction: {
        to: this.LAUNCHPAD_ADDRESS,
        value: ethAmountWei.toString(),
        data: txData,
        gasLimit: '300000', // 估算的gas限制
      },
      estimate: {
        ethAmount: dto.ethAmount,
        tokensToReceive: ethers.formatUnits(tokensToReceive, 18),
        launchId: dto.launchId,
      },
    };
  }

  /**
   * 确认购买交易 - 在钱包交易成功后记录贡献
   */
  async confirmBuyTransaction(dto: ConfirmXLayerBuyDto) {
    try {
      // 验证代币存在
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId: dto.launchId },
      });
      if (!token) throw new Error('Launch not found');

      // 检查代币是否已经毕业（不能再购买）
      if (token.launched) {
        throw new Error('Token has already launched and graduated to DEX. Trading is no longer available on the bonding curve.');
      }

      // 检查代币是否已取消
      if (token.cancelled) {
        throw new Error('Token launch has been cancelled');
      }

      // 连接提供者以获取交易详情
      // 获取交易收据以验证交易成功，使用重试机制
      let receipt = null;
      let attempts = 0;
      const maxAttempts = 5;
      const retryDelay = 2000; // 2秒

      while (attempts < maxAttempts) {
        try {
          receipt = await this.provider.getTransactionReceipt(dto.txHash);
          if (receipt) {
            break;
          }
        } catch (error) {
          console.log(`Attempt ${attempts + 1} failed:`, error.message);
        }
        
        attempts++;
        if (attempts < maxAttempts) {
          console.log(`Waiting ${retryDelay}ms before retry ${attempts + 1}/${maxAttempts}...`);
          await new Promise(resolve => setTimeout(resolve, retryDelay));
        }
      }

      if (!receipt) {
        throw new Error(`Transaction not found after ${maxAttempts} attempts. Hash: ${dto.txHash}`);
      }

      if (receipt.status !== 1) {
        throw new Error('Transaction failed');
      }

      // 验证交易是否是发送到正确的合约地址
      const expectedAddress = this.LAUNCHPAD_ADDRESS.toLowerCase();
      if (receipt.to?.toLowerCase() !== expectedAddress) {
        throw new Error('Transaction not sent to the correct contract');
      }

      // 读取链上最新数据获取实际的代币接收量
      const launchInfo = await this.contractHelper.getLaunchInfo(dto.launchId);

      // 解析交易日志以获取确切的代币购买信息
      const contract = new ethers.Contract(
        expectedAddress,
        [
          'event TokensBought(uint256 indexed launchId, address indexed buyer, uint256 ethAmount, uint256 tokensReceived, uint256 newPrice)',
        ],
        this.provider,
      );

      // 解析交易日志以获取确切的代币购买信息
      const eventContract = new ethers.Contract(
        expectedAddress,
        [
          'event TokensBought(uint256 indexed launchId, address indexed buyer, uint256 ethAmount, uint256 tokensReceived, uint256 newPrice)',
        ],
        this.provider,
      );

      // 查找 TokensBought 事件
      const logs = receipt.logs;
      let tokensReceived = '0';
      let newPrice = '0';

      for (const log of logs) {
        try {
          const parsedLog = contract.interface.parseLog(log);
          if (
            parsedLog &&
            parsedLog.name === 'TokensBought' &&
            parsedLog.args.launchId.toString() === dto.launchId.toString() &&
            parsedLog.args.buyer.toLowerCase() ===
              dto.buyerAddress.toLowerCase()
          ) {
            tokensReceived = ethers.formatUnits(
              parsedLog.args.tokensReceived,
              18,
            );
            newPrice = ethers.formatUnits(parsedLog.args.newPrice, 18);
            break;
          }
        } catch (e) {
          // 忽略解析失败的日志
          continue;
        }
      }

      // 如果没有找到事件，使用估算值
      if (tokensReceived === '0') {
        // 根据 ETH 数量和价格估算代币数量
        const ethAmountWei = ethers.parseEther(dto.ethAmount.toString());
        const calculatorContract = new ethers.Contract(
          expectedAddress,
          [
            'function calculateTokensForETH(uint256 _launchId, uint256 _ethAmount) external view returns (uint256)',
          ],
          this.provider,
        );
        const estimatedTokens = await calculatorContract.calculateTokensForETH(
          dto.launchId,
          ethAmountWei,
        );
        tokensReceived = ethers.formatUnits(estimatedTokens, 18);
      }

      // 检查是否已经记录了这个交易的贡献
      const existingContribution =
        await this.databaseService.xLayerContribution.findFirst({
          where: { txHash: dto.txHash },
        });

      if (existingContribution) {
        return {
          success: true,
          message: 'Contribution already recorded',
          contribution: existingContribution,
        };
      }

      // 创建贡献记录
      const contribution = await this.databaseService.xLayerContribution.create(
        {
          data: {
            launchId: dto.launchId,
            contributor: dto.buyerAddress,
            amount: dto.ethAmount.toString(),
            tokensReceived: tokensReceived,
            tradeType: 'buy',
            txHash: dto.txHash,
            timestamp: Math.floor(Date.now() / 1000),
          },
        },
      );

      // 更新代币信息
      await this.databaseService.xLayerToken.updateMany({
        where: { launchId: dto.launchId },
        data: {
          raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
          tokenPrice: ethers.formatEther(launchInfo.currentPrice),    // 更新前端显示的价格
          currentPrice: ethers.formatEther(launchInfo.currentPrice),  // 保持一致性
          tokensSold: ethers.formatEther(launchInfo.tokensSold), // 添加 tokensSold 更新
          launched: launchInfo.launched, // 同步智能合约中的发射状态
        },
      });

      // 检查是否达到毕业条件（80%筹资目标）
      const currentToken = await this.databaseService.xLayerToken.findFirst({
        where: { launchId: dto.launchId },
      });
      
      if (currentToken && !launchInfo.launched) {
        const raisedAmount = parseFloat(ethers.formatEther(launchInfo.raisedAmount));
        const targetAmount = parseFloat(currentToken.targetAmount);
        const graduationThreshold = 0.8; // 80%
        
        console.log(`Graduation check for launch ${dto.launchId}:`, {
          raisedAmount,
          targetAmount,
          threshold: targetAmount * graduationThreshold,
          percentage: (raisedAmount / targetAmount * 100).toFixed(2) + '%',
          shouldGraduate: raisedAmount >= targetAmount * graduationThreshold
        });
        
        if (raisedAmount >= targetAmount * graduationThreshold) {
          console.log(`🎉 Launch ${dto.launchId} should graduate! Raised ${raisedAmount} OKB >= ${targetAmount * graduationThreshold} OKB`);
          
          // 检查智能合约状态，可能已经自动毕业了
          const updatedLaunchInfo = await this.contractHelper.getLaunchInfo(dto.launchId);
          console.log(`Updated launch info from contract:`, {
            launched: updatedLaunchInfo.launched,
            raisedAmount: ethers.formatEther(updatedLaunchInfo.raisedAmount),
            targetAmount: ethers.formatEther(updatedLaunchInfo.targetAmount)
          });
          
          if (updatedLaunchInfo.launched) {
            console.log(`✅ Launch ${dto.launchId} already graduated on-chain, updating database`);
            await this.databaseService.xLayerToken.updateMany({
              where: { launchId: dto.launchId },
              data: { launched: true },
            });
          } else {
            console.log(`⚠️ Launch ${dto.launchId} should graduate but hasn't on-chain yet. This might be a timing issue.`);
            // 可能需要稍等片刻让智能合约处理
            setTimeout(async () => {
              try {
                const recheckInfo = await this.contractHelper.getLaunchInfo(dto.launchId);
                if (recheckInfo.launched) {
                  console.log(`✅ Launch ${dto.launchId} graduated on recheck, updating database`);
                  await this.databaseService.xLayerToken.updateMany({
                    where: { launchId: dto.launchId },
                    data: { launched: true },
                  });
                }
              } catch (error) {
                console.error(`Error rechecking launch ${dto.launchId}:`, error);
              }
            }, 5000); // 5秒后重新检查
          }
        }
      }

      // 更新数据库中的代币价格（如果从链上获取到了新价格）
      if (newPrice !== '0') {
        try {
          await this.databaseService.xLayerToken.updateMany({
            where: { launchId: dto.launchId },
            data: { 
              tokenPrice: newPrice,    // 更新前端显示的价格
              currentPrice: newPrice,  // 也更新 currentPrice 字段保持一致
              // 也可以更新最后更新时间
              updatedAt: new Date()
            },
          });
          console.log(`✅ Updated token price for launch ${dto.launchId} to ${newPrice} OKB`);
        } catch (updateError) {
          console.error('Error updating token price in database:', updateError);
        }
      }

      // 广播代币价格更新
      try {
        const updatedToken = await this.databaseService.xLayerToken.findFirst({
          where: { launchId: dto.launchId },
        });
        
        if (updatedToken && this.realtimeGateway) {
          // 广播代币更新事件
          this.realtimeGateway.server.emit('xlayer_token_update', {
            id: updatedToken.id,
            launchId: updatedToken.launchId,
            tokenPrice: newPrice,
            raisedAmount: updatedToken.raisedAmount,
            marketCap: updatedToken.marketCap,
            timestamp: new Date().toISOString(),
          });
        }
      } catch (broadcastError) {
        console.error('Error broadcasting token update:', broadcastError);
        // 不要因为广播失败而影响主要逻辑
      }

      return {
        success: true,
        message: 'Buy transaction confirmed and contribution recorded',
        contribution,
        tokensReceived,
        newPrice,
      };
    } catch (error) {
      console.error('Error confirming buy transaction:', error);
      throw error;
    }
  }

  /**
   * 准备卖出交易 - 返回交易数据供前端钱包签名
   */
  async prepareSellTransaction(dto: PrepareXLayerSellDto) {
    // 验证代币存在
    const token = await this.databaseService.xLayerToken.findFirst({
      where: { launchId: dto.launchId },
    });
    if (!token) throw new Error('Launch not found');

    // 生成交易数据
    const contract = new ethers.Contract(
      this.LAUNCHPAD_ADDRESS,
      [
        'function sellTokens(uint256 _launchId, uint256 _tokenAmount) external',
        'function calculateETHForTokens(uint256 _launchId, uint256 _tokenAmount) external view returns (uint256)',
      ],
      this.provider,
    );

    // 计算将获得的ETH数量
    const tokenAmountWei = ethers.parseUnits(dto.tokenAmount.toString(), 18);
    const ethToReceive = await contract.calculateETHForTokens(
      dto.launchId,
      tokenAmountWei,
    );

    // 构建交易数据
    const txData = contract.interface.encodeFunctionData('sellTokens', [
      dto.launchId,
      tokenAmountWei,
    ]);

    return {
      success: true,
      transaction: {
        to: this.LAUNCHPAD_ADDRESS,
        value: '0',
        data: txData,
        gasLimit: '300000', // 估算的gas限制
      },
      estimate: {
        tokenAmount: dto.tokenAmount,
        ethToReceive: ethers.formatEther(ethToReceive),
        launchId: dto.launchId,
      },
    };
  }

  /**
   * 准备授权交易 - 在卖出代币前需要先授权
   */
  async prepareApproveTransaction(dto: PrepareXLayerApproveDto) {
    // 验证代币存在并获取代币地址
    const token = await this.databaseService.xLayerToken.findFirst({
      where: { launchId: dto.launchId },
    });
    if (!token) throw new Error('Launch not found');

    // 生成授权交易数据
    // 获取代币合约信息
    const launchpadContract = new ethers.Contract(
      this.LAUNCHPAD_ADDRESS,
      [
        'function getLaunchInfo(uint256 _launchId) external view returns (address tokenAddress, address creator, string memory name, string memory symbol, string memory description, uint256 targetAmount, uint256 raisedAmount, uint256 deadline, bool launched, bool cancelled, uint256 currentPrice, uint256 tokensSold, uint256 totalSupplyForSale)',
      ],
      this.provider,
    );

    const launchInfo = await launchpadContract.getLaunchInfo(dto.launchId);
    const tokenAddress = launchInfo[0]; // tokenAddress 是返回数组的第一个元素

    // ERC20 合约 ABI 中的 approve 函数
    const erc20Interface = new ethers.Interface([
      'function approve(address spender, uint256 amount) external returns (bool)',
    ]);

    // 构建授权交易数据
    const tokenAmountWei = ethers.parseUnits(dto.tokenAmount.toString(), 18);
    const approveData = erc20Interface.encodeFunctionData('approve', [
      this.LAUNCHPAD_ADDRESS,
      tokenAmountWei,
    ]);

    return {
      success: true,
      transaction: {
        to: tokenAddress, // 发送到代币合约地址
        value: '0', // 授权交易不需要发送ETH
        data: approveData,
        gasLimit: '100000', // 授权交易的gas限制通常较低
      },
      estimate: {
        tokenAmount: dto.tokenAmount,
        spender: this.LAUNCHPAD_ADDRESS,
        launchId: dto.launchId,
        tokenAddress: tokenAddress,
      },
    };
  }

  /**
   * 准备创建代币交易 - 返回交易数据供前端钱包签名
   */
  async prepareCreateTransaction(dto: PrepareXLayerCreateDto) {
    // 构建交易数据
    const contract = new ethers.Contract(
      this.LAUNCHPAD_ADDRESS,
      [
        'function createTokenLaunch(string memory _name, string memory _symbol, string memory _description, string memory _website, string memory _telegram, string memory _twitter, uint256 _targetAmount) external payable',
      ],
      this.provider,
    );

    // 将目标金额转换为wei
    const targetAmountWei = ethers.parseEther(dto.targetAmount.toString());

    // 总创建费用：只收取合约要求的0.01 OKB
    const contractFeeWei = ethers.parseEther('0.01'); // 给合约的费用

    // 构建合约交易数据 (只发送合约费用给合约)
    const txData = contract.interface.encodeFunctionData('createTokenLaunch', [
      dto.name,
      dto.symbol,
      dto.description,
      dto.website || '',
      dto.telegram || '',
      dto.twitter || '',
      targetAmountWei,
    ]);

    // 设置更保守的gas费用，避免钱包拒绝
    const targetGasFeeWei = ethers.parseEther('0.005'); // 降低到0.005 OKB
    const gasLimit = 600000n; // 降低gas limit

    // 反向计算需要的gas价格
    const gasPriceWei = targetGasFeeWei / gasLimit;

    // 总费用 = 合约费 + gas费
    const totalCostWei = contractFeeWei + targetGasFeeWei;

    return {
      success: true,
      transaction: {
        to: this.LAUNCHPAD_ADDRESS,
        value: contractFeeWei.toString(),
        data: txData,
        gasLimit: '600000', // 降低gas limit
        gasPrice: gasPriceWei.toString(),
        description: 'Token creation transaction',
      },
      estimate: {
        name: dto.name,
        symbol: dto.symbol,
        targetAmount: dto.targetAmount,
        creationFee: '0.015', // 合约费用 + 降低的gas费用
        gasFee: ethers.formatEther(targetGasFeeWei), // 固定gas费
        totalCost: ethers.formatEther(totalCostWei), // 总费用
        contractFee: '0.01', // 给合约
        platformFee: '0.00', // 不收取平台费用
        creatorAddress: dto.creatorAddress,
      },
    };
  }

  /**
   * 确认代币创建交易 - 解析交易事件并保存代币信息
   */
  async confirmCreateTransaction(dto: ConfirmXLayerCreateDto) {
    // 使用多个 RPC 端点进行重试
    if (!process.env.XLAYER_RPC_URL) {
      throw new Error('XLAYER_RPC_URL environment variable is required');
    }
    const rpcUrls = [process.env.XLAYER_RPC_URL, 'https://xlayerrpc.okx.com'];

    let lastError: Error | null = null;

    for (const rpcUrl of rpcUrls) {
      try {
        console.log(`尝试使用 RPC: ${rpcUrl}`);

        const provider =
          rpcUrl === process.env.XLAYER_RPC_URL
            ? this.provider
            : new ethers.JsonRpcProvider(rpcUrl, undefined, {
                staticNetwork: true,
              });

        // 获取交易收据，带重试
        let receipt = null;
        for (let i = 0; i < 5; i++) {
          try {
            receipt = await provider.getTransactionReceipt(dto.transactionHash);
            if (receipt) break;
            console.log(`交易收据获取失败，重试 ${i + 1}/5`);
            await new Promise((resolve) => setTimeout(resolve, 2000));
          } catch (e) {
            console.log(`获取交易收据失败 (${i + 1}/5):`, e.message);
            if (i === 4) throw e;
            await new Promise((resolve) => setTimeout(resolve, 2000));
          }
        }

        if (!receipt || receipt.status !== 1) {
          throw new Error('交易失败或未确认');
        }

        console.log('Transaction receipt:', {
          hash: receipt.hash,
          status: receipt.status,
          logsCount: receipt.logs.length,
          logs: receipt.logs.map((log) => ({
            address: log.address,
            topics: log.topics,
            data: log.data,
          })),
        });

        // 解析合约事件 - 使用正确的事件结构
        const contractAddress = this.LAUNCHPAD_ADDRESS.toLowerCase();

        // TokenLaunchCreated 事件的事件签名
        // event TokenLaunchCreated(uint256 indexed launchId, address indexed creator, address tokenAddress, string name, string symbol, uint256 targetAmount)
        const eventSignature = ethers.id(
          'TokenLaunchCreated(uint256,address,address,string,string,uint256)',
        );

        console.log('Looking for event signature:', eventSignature);

        let launchId: number | null = null;
        let tokenAddress: string | null = null;
        let eventName: string | null = null;
        let eventSymbol: string | null = null;
        let eventTargetAmount: string | null = null;

        // 查找来自合约的事件
        for (const log of receipt.logs) {
          console.log('Processing log:', {
            address: log.address.toLowerCase(),
            contractAddress,
            addressMatch: log.address.toLowerCase() === contractAddress,
            topics: log.topics,
            topicMatch: log.topics[0] === eventSignature,
          });

          // 检查是否是我们的合约发出的 TokenLaunchCreated 事件
          if (
            log.address.toLowerCase() === contractAddress &&
            log.topics[0] === eventSignature
          ) {
            try {
              // 手动解析事件数据
              const abiCoder = ethers.AbiCoder.defaultAbiCoder();

              // 解析 indexed 参数 (topics)
              if (log.topics.length >= 3) {
                launchId = Number(ethers.toBigInt(log.topics[1])); // launchId (indexed)
                // creator = ethers.getAddress('0x' + log.topics[2].slice(26)); // creator (indexed)
              }

              // 解析 data 部分 (非 indexed 参数)
              // 根据事件定义: address tokenAddress, string name, string symbol, uint256 targetAmount
              const decodedData = abiCoder.decode(
                ['address', 'string', 'string', 'uint256'],
                log.data,
              );

              tokenAddress = decodedData[0]; // tokenAddress
              eventName = decodedData[1]; // name
              eventSymbol = decodedData[2]; // symbol
              eventTargetAmount = decodedData[3].toString(); // targetAmount

              console.log('Manually parsed event:', {
                launchId,
                tokenAddress,
                name: eventName,
                symbol: eventSymbol,
                targetAmount: eventTargetAmount,
              });

              if (launchId !== null && launchId !== undefined && tokenAddress) {
                break;
              }
            } catch (e) {
              console.log('Manual parsing failed:', e.message);
              continue;
            }
          }
        }

        if (launchId === null || launchId === undefined || !tokenAddress) {
          console.warn('无法从交易事件中提取代币信息，使用备用方案');
          // 备用方案：生成临时数据
          launchId = Math.floor(Math.random() * 1000000); // 临时 launch ID
          tokenAddress = '0x0000000000000000000000000000000000000000'; // 占位符地址

          console.log('Using fallback data:', { launchId, tokenAddress });
        }

        // 保存到数据库
        const result = await this.databaseService.query(
          `
          INSERT INTO xlayer_tokens (
            id, launch_id, token_address, creator, name, symbol, description,
            website, telegram, twitter, image_url, target_amount, raised_amount,
            token_price, created_at, deadline, launched, cancelled, transaction_hash
          ) VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
          RETURNING *
        `,
          [
            launchId,
            tokenAddress,
            dto.creatorAddress,
            eventName || dto.name, // 优先使用事件中的名称
            eventSymbol || dto.symbol, // 优先使用事件中的符号
            dto.description,
            dto.website || null,
            dto.telegram || null,
            dto.twitter || null,
            dto.imageUrl || null,
            eventTargetAmount || dto.targetAmount.toString(), // 优先使用事件中的目标金额
            '0',
            '0.0001', // 默认起始价格
            Math.floor(Date.now() / 1000), // Unix 时间戳 (秒)
            Math.floor((Date.now() + 30 * 24 * 60 * 60 * 1000) / 1000), // 30天后的 Unix 时间戳
            false,
            false,
            dto.transactionHash,
          ],
        );

        const savedToken = result.rows[0];

        // 触发 WebSocket 事件通知前端 (如果需要的话)
        // 这里可以添加事件发射逻辑

        return {
          success: true,
          token: savedToken,
          message: '代币创建成功',
        };
      } catch (error) {
        console.error(`RPC ${rpcUrl} 失败:`, error.message);
        lastError = error;

        // 如果是网络错误，尝试下一个 RPC
        if (
          error.code === 'ECONNRESET' ||
          error.code === 'TIMEOUT' ||
          error.message.includes('socket hang up')
        ) {
          continue;
        }

        // 其他错误直接抛出
        throw error;
      }
    }

    // 所有 RPC 都失败了
    console.error('所有 RPC 端点都失败了');
    throw new Error(
      `确认创建交易失败: ${lastError?.message || '网络连接失败'}`,
    );
  }

  /**
   * 将旧的静态文件URL转换为API端点URL
   */
  private convertImageUrlToApiEndpoint(imageUrl: string): string {
    if (!imageUrl) return imageUrl;

    // 如果已经是API端点格式，直接返回
    if (imageUrl.includes('/api/xlayer/images/')) {
      return imageUrl;
    }

    // 将 /uploads/images/ 格式转换为 /api/xlayer/images/ 格式
    if (imageUrl.includes('/uploads/images/')) {
      const filename = imageUrl.split('/uploads/images/').pop();
      const baseUrl = imageUrl.split('/uploads/images/')[0];
      return `${baseUrl}/api/xlayer/images/${filename}`;
    }

    return imageUrl;
  }

  /**
   * prepareApprove 别名方法，为了兼容控制器调用
   */
  async prepareApprove(launchId: number, dto: PrepareXLayerApproveDto) {
    return await this.prepareApproveTransaction({ ...dto, launchId });
  }

  /**
   * 取消代币发射 (创建者专用)
   */
  async cancelLaunch(
    launchId: number,
    dto: { creatorAddress: string; creatorPrivateKey: string },
  ) {
    try {
      // 验证代币存在
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      if (!token) throw new Error('Launch not found');

      // 验证是创建者
      if (token.creator.toLowerCase() !== dto.creatorAddress.toLowerCase()) {
        throw new Error('Only creator can cancel launch');
      }

      // 验证状态
      if (token.cancelled) throw new Error('Launch already cancelled');
      if (token.launched) throw new Error('Cannot cancel launched token');

      // 调用合约取消
      const contractHelper = new XLayerContractHelper();
      const result = await contractHelper.cancelLaunch({
        launchId,
        creatorPrivateKey: dto.creatorPrivateKey,
      });

      // 更新数据库状态
      await this.databaseService.xLayerToken.update({
        where: { launchId },
        data: { cancelled: true },
      });

      return {
        success: true,
        txHash: result.txHash,
        message: 'Launch cancelled successfully',
      };
    } catch (error) {
      console.error('Cancel launch error:', error);
      throw new Error(`取消发射失败: ${error.message}`);
    }
  }

  /**
   * 准备取消发射交易 (钱包签名用)
   */
  async prepareCancel(launchId: number, dto: { creatorAddress: string }) {
    try {
      // 验证代币存在
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      if (!token) throw new Error('Launch not found');

      // 验证是创建者
      if (token.creator.toLowerCase() !== dto.creatorAddress.toLowerCase()) {
        throw new Error('Only creator can cancel launch');
      }

      // 验证状态
      if (token.cancelled) throw new Error('Launch already cancelled');
      if (token.launched) throw new Error('Cannot cancel launched token');

      // 生成取消交易数据
      const launchpadInterface = new ethers.Interface([
        'function cancelLaunch(uint256 _launchId) external',
      ]);

      const cancelData = launchpadInterface.encodeFunctionData('cancelLaunch', [
        launchId,
      ]);

      return {
        success: true,
        transaction: {
          to: this.LAUNCHPAD_ADDRESS,
          value: '0',
          data: cancelData,
          gasLimit: '100000',
        },
        estimate: {
          launchId,
          creator: dto.creatorAddress,
        },
      };
    } catch (error) {
      console.error('Prepare cancel error:', error);
      throw new Error(`准备取消交易失败: ${error.message}`);
    }
  }

  /**
   * 申请退款 (贡献者专用)
   */
  async claimRefund(
    launchId: number,
    dto: { contributorAddress: string; contributorPrivateKey: string },
  ) {
    try {
      // 验证代币存在
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      if (!token) throw new Error('Launch not found');

      // 验证状态
      if (!token.cancelled) throw new Error('Launch is not cancelled');
      if (token.launched) throw new Error('Cannot refund launched token');

      // 验证用户有贡献
      const contribution =
        await this.databaseService.xLayerContribution.findFirst({
          where: {
            launchId,
            contributor: dto.contributorAddress.toLowerCase(),
          },
        });
      if (!contribution)
        throw new Error('No valid contribution found for refund');

      // 调用合约申请退款
      const contractHelper = new XLayerContractHelper();
      const result = await contractHelper.claimRefund({
        launchId,
        contributorPrivateKey: dto.contributorPrivateKey,
      });

      // TODO: 标记贡献为已退款 (需要等待Prisma客户端更新)
      // await this.databaseService.xLayerContribution.update({
      //   where: { id: contribution.id },
      //   data: { refunded: true },
      // });

      return {
        success: true,
        txHash: result.txHash,
        refundAmount: result.refundAmount
          ? ethers.formatEther(result.refundAmount)
          : contribution.amount,
        message: 'Refund claimed successfully',
      };
    } catch (error) {
      console.error('Claim refund error:', error);
      throw new Error(`申请退款失败: ${error.message}`);
    }
  }

  /**
   * 准备退款交易 (钱包签名用)
   */
  async prepareRefund(launchId: number, dto: { contributorAddress: string }) {
    try {
      console.log(
        `prepareRefund called with launchId: ${launchId}, contributorAddress: ${dto.contributorAddress}`,
      );

      // 验证代币存在
      const token = await this.databaseService.xLayerToken.findFirst({
        where: { launchId },
      });
      console.log(`Token found:`, token);

      if (!token) throw new Error('Launch not found');

      // 检查合约的实际状态
      console.log(`Checking contract status for launch ${launchId}...`);
      let contractLaunchInfo;
      try {
        contractLaunchInfo = await this.contractHelper.getLaunchInfo(launchId);
        console.log(`Contract launch info:`, {
          launched: contractLaunchInfo.launched,
          cancelled: contractLaunchInfo.cancelled,
          raisedAmount: ethers.formatEther(contractLaunchInfo.raisedAmount),
          creator: contractLaunchInfo.creator,
          tokenAddress: contractLaunchInfo.tokenAddress,
          deadline: contractLaunchInfo.deadline,
          currentPrice: ethers.formatEther(contractLaunchInfo.currentPrice),
        });

        // 检查用户是否确实有贡献在合约中
        console.log(`Checking user contribution in contract...`);
        try {
          const contract = new ethers.Contract(
            this.LAUNCHPAD_ADDRESS,
            [
              'function getUserContribution(uint256 _launchId, address _user) external view returns (uint256)',
              'function canClaimRefund(uint256 _launchId, address _user) external view returns (bool)',
            ],
            this.provider,
          );

          try {
            const userContribution = await contract.getUserContribution(
              launchId,
              dto.contributorAddress,
            );
            console.log(
              `User contribution in contract: ${ethers.formatEther(userContribution)} ETH`,
            );

            if (userContribution === 0n) {
              throw new Error(
                `No contribution found in contract for user ${dto.contributorAddress}. Contract shows 0 contribution.`,
              );
            }
          } catch (contributionError) {
            console.warn(
              `Could not check user contribution:`,
              contributionError.message,
            );
          }

          try {
            const canRefund = await contract.canClaimRefund(
              launchId,
              dto.contributorAddress,
            );
            console.log(`Can user claim refund: ${canRefund}`);

            if (!canRefund) {
              throw new Error(
                `User ${dto.contributorAddress} is not eligible for refund according to contract`,
              );
            }
          } catch (refundCheckError) {
            console.warn(
              `Could not check refund eligibility:`,
              refundCheckError.message,
            );
            // 继续执行，因为这个方法可能不存在
          }
        } catch (contractCheckError) {
          console.error(
            `Error checking user status in contract:`,
            contractCheckError,
          );
          // 如果是严重错误，抛出，否则继续
          if (contractCheckError.message.includes('No contribution found')) {
            throw contractCheckError;
          }
        }
      } catch (contractError) {
        console.error(`Error getting contract info:`, contractError);
        throw new Error(
          `Cannot verify contract status: ${contractError.message}`,
        );
      }

      // 验证状态
      if (!contractLaunchInfo.cancelled) {
        throw new Error(
          `Launch is not cancelled in the contract. Contract cancelled status: ${contractLaunchInfo.cancelled}. Please ensure the launch is properly cancelled first.`,
        );
      }
      if (contractLaunchInfo.launched) {
        throw new Error('Cannot refund launched token');
      }

      // 直接从数据库查询用户贡献记录
      console.log(
        `Searching for contribution with launchId: ${launchId}, contributor: ${dto.contributorAddress.toLowerCase()}`,
      );

      // 先查询该 launchId 的所有贡献记录，看看数据库中有什么
      const allContributions =
        await this.databaseService.xLayerContribution.findMany({
          where: { launchId },
        });
      console.log(
        `All contributions for launchId ${launchId}:`,
        allContributions,
      );

      // 然后查询特定用户的贡献记录
      const contribution =
        await this.databaseService.xLayerContribution.findFirst({
          where: {
            launchId,
            contributor: dto.contributorAddress.toLowerCase(),
          },
        });
      console.log(`Contribution search result:`, contribution);

      // 如果没找到，尝试不区分大小写的查询
      if (!contribution) {
        console.log(`Trying case-insensitive search...`);
        const contributionCaseInsensitive =
          await this.databaseService.xLayerContribution.findFirst({
            where: {
              launchId,
              contributor: {
                equals: dto.contributorAddress,
                mode: 'insensitive',
              },
            },
          });
        console.log(
          `Case-insensitive contribution search result:`,
          contributionCaseInsensitive,
        );

        if (contributionCaseInsensitive) {
          // 如果找到了，使用这个记录
          console.log(
            `Found contribution with case-insensitive search, using it`,
          );

          // 获取gas价格信息
          let gasPrice;
          let estimatedGasFee = '0.004';

          try {
            const feeData = await this.provider.getFeeData();
            if (feeData.gasPrice) {
              const doubledGasPrice = feeData.gasPrice * 2n;
              gasPrice = doubledGasPrice.toString();
              estimatedGasFee = ethers.formatEther(doubledGasPrice * 200000n);
            }
          } catch (gasError) {
            gasPrice = ethers.parseUnits('20', 'gwei').toString();
            estimatedGasFee = ethers.formatEther(BigInt(gasPrice) * 200000n);
          }

          // 生成退款交易数据
          const launchpadInterface = new ethers.Interface([
            'function claimRefund(uint256 _launchId) external',
          ]);

          const refundData = launchpadInterface.encodeFunctionData(
            'claimRefund',
            [launchId],
          );

          // 检查是否需要代币批准
          const approvalCheck = await this.checkTokenApproval(
            launchId,
            dto.contributorAddress,
          );

          if (approvalCheck.success && approvalCheck.data.needsApproval) {
            // 需要先批准代币
            return {
              success: false,
              error: 'Token approval required',
              needsApproval: true,
              approvalData: {
                tokenAddress: approvalCheck.data.tokenAddress,
                spenderAddress: this.LAUNCHPAD_ADDRESS,
                requiredAmount: approvalCheck.data.requiredApproval,
                currentAllowance: approvalCheck.data.allowanceToContract,
              },
            };
          }

          return {
            success: true,
            transaction: {
              to: this.LAUNCHPAD_ADDRESS,
              value: '0',
              data: refundData,
              gasLimit: '200000',
              gasPrice: gasPrice,
            },
            estimate: {
              launchId,
              contributor: dto.contributorAddress,
              refundAmount: contributionCaseInsensitive.amount,
              estimatedGasFee: estimatedGasFee,
            },
          };
        }
      }

      if (!contribution) throw new Error('No contribution found');

      // 检查是否需要代币批准
      const approvalCheck = await this.checkTokenApproval(
        launchId,
        dto.contributorAddress,
      );

      if (approvalCheck.success && approvalCheck.data.needsApproval) {
        // 需要先批准代币
        return {
          success: false,
          error: 'Token approval required',
          needsApproval: true,
          approvalData: {
            tokenAddress: approvalCheck.data.tokenAddress,
            spenderAddress: this.LAUNCHPAD_ADDRESS,
            requiredAmount: approvalCheck.data.requiredApproval,
            currentAllowance: approvalCheck.data.allowanceToContract,
          },
        };
      }

      // 生成退款交易数据
      const launchpadInterface = new ethers.Interface([
        'function claimRefund(uint256 _launchId) external',
      ]);

      const refundData = launchpadInterface.encodeFunctionData('claimRefund', [
        launchId,
      ]);

      // 获取当前网络的gas价格并加倍
      let gasPrice;
      let estimatedGasFee = '0.004'; // 默认估算值

      try {
        const feeData = await this.provider.getFeeData();
        if (feeData.gasPrice) {
          // 将gas价格加倍以确保交易能够被快速确认
          const doubledGasPrice = feeData.gasPrice * 2n;
          gasPrice = doubledGasPrice.toString();
          // 计算估算的gas费用 (gasPrice * gasLimit)
          estimatedGasFee = ethers.formatEther(doubledGasPrice * 200000n);
          console.log(
            `Network gas price: ${feeData.gasPrice}, Using doubled gas price: ${gasPrice}, Estimated fee: ${estimatedGasFee} OKB`,
          );
        }
      } catch (gasError) {
        console.warn(
          'Could not fetch gas price, using default:',
          gasError.message,
        );
        // 使用默认较高的gas价格 (20 Gwei)
        gasPrice = ethers.parseUnits('20', 'gwei').toString();
        estimatedGasFee = ethers.formatEther(BigInt(gasPrice) * 200000n);
      }

      return {
        success: true,
        transaction: {
          to: this.LAUNCHPAD_ADDRESS,
          value: '0',
          data: refundData,
          gasLimit: '200000', // 增加gas limit以确保交易成功
          gasPrice: gasPrice, // 添加gas价格
        },
        estimate: {
          launchId,
          contributor: dto.contributorAddress,
          refundAmount: contribution.amount,
          estimatedGasFee: estimatedGasFee, // 添加估算的gas费用
        },
      };
    } catch (error) {
      console.error('Prepare refund error:', error);
      throw new Error(`准备退款交易失败: ${error.message}`);
    }
  }

  /**
   * 确认退款交易 - 在钱包交易成功后更新数据库
   */
  async confirmRefund(
    launchId: number,
    dto: { contributorAddress: string; txHash: string },
  ) {
    try {
      console.log(
        `Confirming refund for launch ${launchId}, contributor ${dto.contributorAddress}, txHash: ${dto.txHash}`,
      );

      // 如果是测试交易哈希，跳过区块链验证
      const isTestTx =
        dto.txHash.startsWith('0x1234567890abcdef') ||
        dto.txHash ===
          '0x0000000000000000000000000000000000000000000000000000000000000000';

      if (!isTestTx) {
        // 验证交易存在且成功
        let receipt = null;
        try {
          receipt = await this.provider.getTransactionReceipt(dto.txHash);
        } catch (receiptError) {
          console.warn(
            'Could not fetch transaction receipt:',
            receiptError.message,
          );
          // 继续执行，可能是网络问题
        }

        if (receipt) {
          if (receipt.status !== 1) {
            throw new Error('Transaction failed');
          }

          // 验证交易是发送到正确的合约
          const expectedAddress = this.LAUNCHPAD_ADDRESS.toLowerCase();
          if (receipt.to?.toLowerCase() !== expectedAddress) {
            throw new Error('Transaction not sent to the correct contract');
          }
        }
      }

      // 查找用户的贡献记录
      const contribution =
        await this.databaseService.xLayerContribution.findFirst({
          where: {
            launchId,
            contributor: {
              equals: dto.contributorAddress,
              mode: 'insensitive',
            },
          },
        });

      if (!contribution) {
        throw new Error('No contribution found for this user');
      }

      if (contribution.refunded) {
        return {
          success: true,
          message: 'Refund already recorded',
          contribution,
        };
      }

      // 更新贡献记录为已退款
      const updatedContribution =
        await this.databaseService.xLayerContribution.update({
          where: { id: contribution.id },
          data: {
            refunded: true,
            // 添加退款交易哈希，保留原始的购买交易哈希
            refundTxHash: dto.txHash, // 退款交易的哈希
          },
        });

      console.log(
        `Refund confirmed and recorded for contribution ${contribution.id}`,
      );

      return {
        success: true,
        message: 'Refund confirmed successfully',
        contribution: updatedContribution,
        refundAmount: contribution.amount,
      };
    } catch (error) {
      console.error('Error confirming refund:', error);
      throw new Error(`确认退款失败: ${error.message}`);
    }
  }

  /**
   * 从区块链同步用户的贡献历史
   * 用于恢复缺失的贡献记录
   */
  async syncUserContributionsFromBlockchain(
    launchId: number,
    userAddress: string,
  ) {
    try {
      console.log(
        `Syncing contributions for user ${userAddress} in launch ${launchId}...`,
      );

      const contractAddress = this.LAUNCHPAD_ADDRESS;

      const contract = new ethers.Contract(
        contractAddress,
        [
          'event TokensBought(uint256 indexed launchId, address indexed buyer, uint256 ethAmount, uint256 tokensReceived, uint256 newPrice)',
        ],
        this.provider,
      );

      // 查找该用户在该启动中的所有购买事件
      const filter = contract.filters.TokensBought(launchId, userAddress);

      // 获取当前区块号
      const currentBlock = await this.provider.getBlockNumber();
      console.log(`Current block: ${currentBlock}`);

      // 从较近的区块开始查找（最近10000个区块）
      const startBlock = Math.max(0, currentBlock - 10000);
      const batchSize = 1000; // XLayer的最大查询范围

      console.log(
        `Querying from block ${startBlock} to ${currentBlock} in batches of ${batchSize}`,
      );

      let allEvents: any[] = [];

      for (
        let fromBlock = startBlock;
        fromBlock <= currentBlock;
        fromBlock += batchSize
      ) {
        const toBlock = Math.min(fromBlock + batchSize - 1, currentBlock);

        try {
          console.log(`Querying blocks ${fromBlock} to ${toBlock}`);
          const events = await contract.queryFilter(filter, fromBlock, toBlock);
          allEvents = allEvents.concat(events);
          console.log(
            `Found ${events.length} events in block range ${fromBlock}-${toBlock}`,
          );
        } catch (batchError) {
          console.error(
            `Error querying blocks ${fromBlock}-${toBlock}:`,
            batchError.message,
          );
          // 继续下一个批次
          continue;
        }
      }

      console.log(
        `Found total ${allEvents.length} purchase events for user ${userAddress}`,
      );

      for (const event of allEvents) {
        // 确保事件是 EventLog 类型且有 args
        if ('args' in event && event.args) {
          const args = event.args;
          const txHash = event.transactionHash;
          const ethAmount = ethers.formatEther(args.ethAmount);
          const tokensReceived = ethers.formatUnits(args.tokensReceived, 18);

          // 检查是否已经记录了这个交易
          const existingContribution =
            await this.databaseService.xLayerContribution.findFirst({
              where: { txHash },
            });

          if (!existingContribution) {
            // 获取交易的时间戳
            const receipt = await this.provider.getTransactionReceipt(txHash);
            const block = await this.provider.getBlock(receipt.blockNumber);
            const timestamp = block
              ? block.timestamp
              : Math.floor(Date.now() / 1000);

            // 创建贡献记录
            await this.databaseService.xLayerContribution.create({
              data: {
                launchId: parseInt(args.launchId.toString()),
                contributor: args.buyer.toLowerCase(),
                amount: ethAmount,
                tokensReceived: tokensReceived,
                tradeType: 'buy',
                txHash: txHash,
                timestamp: timestamp,
              },
            });

            console.log(
              `Synced contribution: ${txHash}, ETH: ${ethAmount}, Tokens: ${tokensReceived}`,
            );
          } else {
            console.log(`Contribution already exists for tx: ${txHash}`);
          }
        }
      }

      console.log(
        `Sync completed for user ${userAddress} in launch ${launchId}`,
      );
    } catch (error) {
      console.error('Error syncing user contributions from blockchain:', error);
      // 不抛出错误，因为这是一个恢复机制
    }
  }

  /**
   * 从合约检查启动状态 - 用于调试
   */
  async checkLaunchStatusFromContract(launchId: number) {
    try {
      const launchInfo = await this.contractHelper.getLaunchInfo(launchId);
      console.log(`Contract launch info for ${launchId}:`, {
        launched: launchInfo.launched,
        cancelled: launchInfo.cancelled,
        raisedAmount: ethers.formatEther(launchInfo.raisedAmount),
        currentPrice: ethers.formatEther(launchInfo.currentPrice),
        creator: launchInfo.creator,
        tokenAddress: launchInfo.tokenAddress,
      });
      return launchInfo;
    } catch (error) {
      console.error('Error checking launch status from contract:', error);
      throw error;
    }
  }

  /**
   * 测试退款调用 - 用于调试合约错误
   */
  async testRefundCall(launchId: number, userAddress: string) {
    try {
      console.log(
        `Testing refund call for launch ${launchId}, user ${userAddress}...`,
      );

      const contract = new ethers.Contract(
        this.LAUNCHPAD_ADDRESS,
        [
          'function claimRefund(uint256 _launchId) external',
          'function getUserContribution(uint256 _launchId, address _user) external view returns (uint256)',
          'function getLaunchInfo(uint256 _launchId) external view returns (address tokenAddress, address creator, string memory name, string memory symbol, string memory description, uint256 targetAmount, uint256 raisedAmount, uint256 deadline, bool launched, bool cancelled, uint256 currentPrice, uint256 tokensSold, uint256 totalSupplyForSale)',
          'mapping(uint256 => mapping(address => uint256)) public contributions',
          'mapping(uint256 => mapping(address => bool)) public hasClaimedRefund',
          'event RefundClaimed(uint256 indexed launchId, address indexed user, uint256 amount)',
        ],
        this.provider,
      );

      // 1. 检查启动信息
      console.log('1. Checking launch info...');
      const launchInfo = await contract.getLaunchInfo(launchId);
      console.log('Launch info:', {
        tokenAddress: launchInfo[0],
        creator: launchInfo[1],
        name: launchInfo[2],
        launched: launchInfo[8],
        cancelled: launchInfo[9],
        raisedAmount: ethers.formatEther(launchInfo[6]),
      });

      // 2. 检查用户贡献
      console.log('2. Checking user contribution...');
      try {
        const userContribution = await contract.getUserContribution(
          launchId,
          userAddress,
        );
        console.log(
          'User contribution:',
          ethers.formatEther(userContribution),
          'ETH',
        );
      } catch (e) {
        console.log('getUserContribution not available or failed:', e.message);
      }

      // 2a. 检查contributions映射
      try {
        const directContribution = await contract.contributions(
          launchId,
          userAddress,
        );
        console.log(
          'Direct contribution from mapping:',
          ethers.formatEther(directContribution),
          'ETH',
        );

        if (directContribution === 0n) {
          console.log(
            '❌ User has ZERO contribution in contract! This explains the error.',
          );
          return {
            success: false,
            error: 'User has no contribution recorded in the contract',
            reason: 'contributions mapping shows 0 for this user',
            launchInfo: {
              launched: launchInfo[8],
              cancelled: launchInfo[9],
              raisedAmount: ethers.formatEther(launchInfo[6]),
            },
          };
        }
      } catch (e) {
        console.log('Direct contributions mapping not available:', e.message);
      }

      // 2b. 检查是否已经申请过退款
      try {
        const hasClaimedRefund = await contract.hasClaimedRefund(
          launchId,
          userAddress,
        );
        console.log('Has already claimed refund:', hasClaimedRefund);
      } catch (e) {
        console.log('hasClaimedRefund mapping not available:', e.message);
      }

      // 3. 尝试估算gas
      console.log('3. Estimating gas for refund call...');
      try {
        const gasEstimate = await contract.claimRefund.estimateGas(launchId, {
          from: userAddress,
        });
        console.log('Gas estimate:', gasEstimate.toString());
      } catch (gasError) {
        console.error('Gas estimation failed:', gasError);

        // 尝试解析错误
        if (gasError.data) {
          console.log('Error data:', gasError.data);
        }

        // 检查合约余额
        console.log('4. Checking contract balance...');
        try {
          const contractBalance = await this.provider.getBalance(
            this.LAUNCHPAD_ADDRESS,
          );
          console.log(
            'Contract balance:',
            ethers.formatEther(contractBalance),
            'ETH',
          );
        } catch (balanceError) {
          console.log(
            'Could not check contract balance:',
            balanceError.message,
          );
        }

        // 检查用户是否已经退款过
        console.log('5. Checking if user already claimed refund...');
        try {
          const events = await contract.queryFilter(
            contract.filters.RefundClaimed(launchId, userAddress),
            -1000, // 最近1000个区块
            'latest',
          );
          console.log('Previous refund events for user:', events.length);
          if (events.length > 0) {
            console.log('User has already claimed refund!');
          }
        } catch (eventError) {
          console.log('Could not check refund events:', eventError.message);
        }

        return {
          success: false,
          error: gasError.message,
          errorData: gasError.data,
          launchInfo: {
            launched: launchInfo[8],
            cancelled: launchInfo[9],
            raisedAmount: ethers.formatEther(launchInfo[6]),
          },
          contractBalance: await this.provider
            .getBalance(this.LAUNCHPAD_ADDRESS)
            .then((b) => ethers.formatEther(b))
            .catch(() => 'unknown'),
        };
      }

      return {
        success: true,
        launchInfo: {
          launched: launchInfo[8],
          cancelled: launchInfo[9],
          raisedAmount: ethers.formatEther(launchInfo[6]),
        },
      };
    } catch (error) {
      console.error('Error testing refund call:', error);
      return {
        success: false,
        error: error.message,
      };
    }
  }

  /**
   * 测试退一半金额 - 检查是否是合约余额问题
   */
  async testHalfRefund(launchId: number, userAddress: string) {
    try {
      console.log(
        `Testing half refund for launch ${launchId}, user ${userAddress}...`,
      );

      // 先检查数据库中的贡献记录
      const contribution =
        await this.databaseService.xLayerContribution.findFirst({
          where: {
            launchId,
            contributor: {
              equals: userAddress,
              mode: 'insensitive',
            },
          },
        });

      if (!contribution) {
        return {
          success: false,
          error: 'No contribution found in database',
        };
      }

      const originalAmount = parseFloat(contribution.amount);
      const halfAmount = originalAmount / 2;

      console.log('Contribution details:', {
        original: contribution.amount + ' ETH',
        half: halfAmount + ' ETH',
        tokens: contribution.tokensReceived,
      });

      // 但是现在的问题是：用户在合约中没有贡献记录
      // 这意味着要么：
      // 1. 用户已经申请过退款
      // 2. 用户卖出了所有代币（清零了贡献）
      // 3. 购买时没有正确记录到合约

      // 让我们检查用户是否曾经卖出过代币
      console.log('Checking if user may have sold tokens...');

      return {
        success: false,
        error: 'User has zero contribution in contract',
        analysis: {
          databaseAmount: contribution.amount,
          contractAmount: '0',
          possibleCauses: [
            'User already claimed refund',
            'User sold all tokens (which zeros out contributions)',
            'Purchase was not properly recorded in contract',
          ],
        },
      };
    } catch (error) {
      console.error('Error testing half refund:', error);
      return {
        success: false,
        error: error.message,
      };
    }
  }

  /**
   * 检查代币批准状态 - 用于退款
   */
  async checkTokenApproval(launchId: number, userAddress: string) {
    try {
      console.log(
        `Checking token approval for launch ${launchId}, user ${userAddress}...`,
      );

      // 获取代币地址
      const contract = new ethers.Contract(
        this.LAUNCHPAD_ADDRESS,
        [
          'function getLaunchInfo(uint256 _launchId) external view returns (address tokenAddress, address creator, string memory name, string memory symbol, string memory description, uint256 targetAmount, uint256 raisedAmount, uint256 deadline, bool launched, bool cancelled, uint256 currentPrice, uint256 tokensSold, uint256 totalSupplyForSale)',
          'function getUserContribution(uint256 _launchId, address _user) external view returns (uint256)',
          'function getUserTokenBalance(uint256 _launchId, address _user) external view returns (uint256)',
        ],
        this.provider,
      );

      const launchInfo = await contract.getLaunchInfo(launchId);
      const tokenAddress = launchInfo[0];

      console.log('Token address:', tokenAddress);

      if (!tokenAddress || tokenAddress === ethers.ZeroAddress) {
        return {
          success: false,
          error: 'Invalid token address',
        };
      }

      // 检查用户的代币余额和批准状态
      const tokenContract = new ethers.Contract(
        tokenAddress,
        [
          'function balanceOf(address) external view returns (uint256)',
          'function allowance(address owner, address spender) external view returns (uint256)',
        ],
        this.provider,
      );

      // 检查用户在合约中记录的代币余额
      const contractTokenBalance = await contract.getUserTokenBalance(
        launchId,
        userAddress,
      );

      // 检查用户实际持有的代币余额
      const userTokenBalance = await tokenContract.balanceOf(userAddress);

      // 检查用户批准给合约的代币数量
      const allowance = await tokenContract.allowance(
        userAddress,
        this.LAUNCHPAD_ADDRESS,
      );

      console.log('Token balances and approvals:', {
        contractRecordedBalance: ethers.formatEther(contractTokenBalance),
        userActualBalance: ethers.formatEther(userTokenBalance),
        allowanceToContract: ethers.formatEther(allowance),
        needsApproval: contractTokenBalance > allowance,
      });

      return {
        success: true,
        data: {
          tokenAddress,
          contractRecordedBalance: ethers.formatEther(contractTokenBalance),
          userActualBalance: ethers.formatEther(userTokenBalance),
          allowanceToContract: ethers.formatEther(allowance),
          needsApproval: contractTokenBalance > allowance,
          requiredApproval: ethers.formatEther(contractTokenBalance),
        },
      };
    } catch (error) {
      console.error('Error checking token approval:', error);
      return {
        success: false,
        error: error.message,
      };
    }
  }
}
